#ifndef TILEMANAGER_CPP
#define TILEMANAGER_CPP

#include "TileManager.h"  
class Floor;
TileManager* TileManager::getInstance(SDL_Surface * result, SDL_Surface * screen)
{
	return NULL;
	//unimplemented. for singleton
}


TileManager::TileManager( SDL_Surface * result, SDL_Surface * screen)
{
	 
	tileset = result; //location of the tileset image
	TileManager::screen = screen;//store the screen so we can draw to it from the tileManager


	int across = SCREEN_HEIGHT/TILE_SIZE;
	int length = SCREEN_WIDTH/TILE_SIZE;
	for (int i = 0 ; i<NUM_TILES_X; i++)
	{
		for (int j = 0 ; j<NUM_TILES_Y;j++)
		{
			tileArray[i][j] = new Tile();
			  
	//should instead create a drawable Floor object that gets added to every tile
		}

	}


	/*'creates the screen'. for every TILESIZE X TILESIZE squa re,
	we create a tile, and map it to a coordinate
	it might be prudent to create more tiles than what can appear on the screen.
	at this point,no tile has any graphic applied to it. We merely have every coordinate
	created with an SDL_Rect so we can get that rect and draw to it.
	tiles are black when they are created*/

	for(int i = 0 ; i<NUM_IMAGES; i++)
	{
		images[i].h = TILE_SIZE;
		images[i].w = TILE_SIZE;
		images[i].x = (i%TILESET_WIDTH)*TILE_SIZE;
		images[i].y = (i/TILESET_WIDTH)*TILE_SIZE;
	}

}

void TileManager::spawn( Drawable* thing, int x, int y)
{ 
	Tile* tile = getTile(x, y);
	tile->drawables.push_back(*thing); 
	thing->setXY(x,y);
}

/*
takes a cardinal direction as a char*. using any other char* results in no movement.
takes a drawable thing and moves it spaces number of spaces in direction direction
returns true if the object moved
*/
bool TileManager::move( Drawable* thing, int spaces, char* direction)
{
	bool moved = false;
	if(spaces<1)
		return false;
	/*convert strings for the switch. only necessary for multiple char
	directions like SE and NW. The numbers used here relate the cardinal 
	directions with keys on the numpad, to make it easier to read. 
	(9=NE, 1=SW, 3=SE, 7=NW)*/

	if(direction == "NE")
		direction = "9"; 
	if(direction == "SE")
		direction = "3"; 
	if(direction == "NW")
		direction = "7"; 
	if(direction == "SW")
		direction = "1"; 



	int x = thing->getX();
	int y = thing->y;

	Tile* currentTile = tileArray[x][y];
	switch(*direction)
	{
	case 'N'://going up, y gets smaller
		y-=spaces;

		break;
	case 'E'://right, x gets bigger
		x += spaces;
		break;
	case 'S': //down, y gets bigger
		y+=spaces;
		break;
	case 'W'://left, x gets smaller
		x-=spaces;
		break;
	case '9': //NE

		if(x>=NUM_TILES_X-1 || y<=0)
			return false;
		x+=spaces;
		y-=spaces;
		break;
	case '7'://NW
		if(x<=0||y<=0)
			return false;
		x-=spaces;
		y-=spaces;
		break;
	case '1'://SW
		if(x<=0 || y>=NUM_TILES_Y-1)
			return false;
		x-=spaces;
		y+=spaces;
		break;
	case '3': //SE
		if(x>=NUM_TILES_X-1||y>=NUM_TILES_Y-1)
			return false;
		x+=spaces;
		y+=spaces;
	default:
		break;

	}
	if(x<0)
		x=0;
	if(y<0)
		y=0;
	if(x>=NUM_TILES_X)
		x=NUM_TILES_X - 1;
	if(y>=NUM_TILES_Y)
		y= NUM_TILES_Y -1;
	Tile* newTile = getTile(x,y);
	if(!newTile->Collides(-1))
	{
		
	currentTile->removeDrawable(thing->uid);
	newTile->addDrawable(thing); 
//	newTile->applyGraphics();
	thing->setXY(x,y);
	
	return true;
	}
	else
	{
		return false;
	}
	//NOTE: the return value is NOT ALWAYS VALID HERE.
	//need to come up with a complete way of indicating whether movement occured
	//as it is now, rare instances cause this return value to be inaccurate
	//however the return value isn't used at all yet so  I don't really give a fuck right now
}

int TileManager::getIndex(int x, int y, bool isInScreenCoords)
{
	if(isInScreenCoords)
		return ((x/TILE_SIZE) + ((y/TILE_SIZE)*TILESET_WIDTH));
	return (x+(y*TILESET_WIDTH));

}
 
Tile* TileManager::getTile(int x, int y)
{
	return tileArray[x][y];

 
}

void TileManager::setTileImage(Tile *tile, int imgID)
{
	Draw::apply_surface(0 , 0 , tileset, tile->tileImage ,  &images[imgID]);

}

void TileManager::update( )//draws all the tiles on the screen. called every frame.
{ 
	 //get rid of this reference to the player and just encapsulate all the distance and shroud shit in the player class.
	//createShroud();
	for(int i = 0 ; i<NUM_TILES_X; i++)
	{
		for(int j = 0 ; j < NUM_TILES_Y; j++)
		{
			if(tileArray[i][j]->tileImage!=NULL)
			{
				
				tileArray[i][j]->applyGraphics( );
				Draw::apply_surface(i*TILE_SIZE, j*TILE_SIZE, tileArray[i][j]->tileImage, screen);
			}

		}
		  
	}
	
} 

/*
loop through all tiles, get the highest lightEmitted value in each one
add light variable to tile object.
on update, set light to zero, then add X to it based on it's proximity to lightemitted squares.
*/
void TileManager::createShroud() const//read the game design gem on LOS. it will take time to get it, but implement it their way.
{/*
	double light= 0.0;
	int param=(int)Draw::distanceFormula(1,2,3,4);
	double distance = Draw::distanceFormula(1,2,3,12);
	double lightValues[NUM_TILES_X][NUM_TILES_Y] = {0.0};
	double finalLightValues[NUM_TILES_X][NUM_TILES_Y] ={0.0}; 
	std::stack<Drawable*> emitters = *new std::stack<Drawable*>();
	for(int i = 0 ; i<NUM_TILES_X; i++)
	{
		for(int j = 0 ; j < NUM_TILES_Y; j++)
		{
			//param = tileArray[i][j]->getLightEmitted();
			lightValues[i][j] = tileArray[i][j]->getLightEmitted();
			if(lightValues[i][j]<0.01)
			{ 
				emitters.
					push((tileArray[i][j]->getEmitter()));
			}
		}
		  
	}

while(!emitters.empty()){
		
	Drawable* it = emitters.top();
	for(int i = 0 ; i<NUM_TILES_X; i++)
	{
		for(int j = 0 ; j < NUM_TILES_Y; j++)
		{ 
			distance = Draw::distanceFormula(it->getX()/TILE_SIZE , i , it->getY()/TILE_SIZE , j );
			//if distance from emitter is less than emitted light
			if( distance < ((double) it->lightEmitted))
			{
				light =(double) ((double)it->lightEmitted / distance);
				light /= (double)it->lightEmitted;
				finalLightValues[i][j] = light;
			}
		
		}
		  
	}
	emitters.pop();
}
	  
	for(int i = 0 ; i<NUM_TILES_X; i++)
	{
		for(int j = 0 ; j < NUM_TILES_Y; j++)
		{
			param = (int)(finalLightValues[i][j]*50);
			tileArray[i][j]->setAlpha(param);
		
		}
		  
	} */

} 

void TileManager::applyFloor(Drawable* floor )
{
	
	for(int i = 0 ; i<NUM_TILES_X; i++)
	{
		for(int j = 0 ; j < NUM_TILES_Y; j++)
		{
			if(tileArray[i][j]->tileImage!=NULL)
			{
				tileArray[i][j]->addDrawable(floor);
				tileArray[i][j]->applyGraphics();
				
			}

		}



	}
} 

#endif